//
//  TXFRCDManager.swift
//  Here_Swift
//
//  Created by 童煊 on 2018/1/9.
//  Copyright © 2018年 童煊. All rights reserved.
//

import UIKit

/** fail request central dispatch manager*/
class TXFRCDManager: NSObject {
    
    //默认重复分发最小间隔
    static let FRCDDefaultRepeatTimeInterval : TimeInterval = 0.2
    
    /** 分发处理规则（防抖、节流）*/
    private(set) var dispatchHandleRule : MTRule?
    
    /** 失败请求缓存，最大限制50个，超出则清空缓存*/
    let failRequestCache : TXNetworkTaskCache = TXNetworkTaskCache()
    
    /** 重复分发执行最小间隔*/
    public var repeatTimeInterval : TimeInterval = FRCDDefaultRepeatTimeInterval {
        willSet{
        }
        didSet{
            self.resetMTRule()
        }
    }
    
    /** 重复分发模式,默认节流*/
    public var repeatHandleMode : MTPerformMode = .firstly {
        willSet{
            
        }
        didSet{
            self.resetMTRule()
        }
    }
    
    /** 共享单例*/
    static let fRCDManager : TXFRCDManager = TXFRCDManager()
    
    /**
     @return 管理类单例
     */
    class func sharedManager() -> TXFRCDManager {
        return fRCDManager
    }
    
    /** 重载初始化方法*/
    override init() {
        super.init()
        self.failRequestCache.addObserver(self, forKeyPath: "cache", options: NSKeyValueObservingOptions.new, context: nil)
        self.dispatchHandleRule = self.mt_limitSelector(#selector(dispatchFailRequestHandler_ModeRepeat_WithModel(model:)), oncePerDuration: self.repeatTimeInterval, using: self.repeatHandleMode)
        MTEngine.default.apply(self.dispatchHandleRule!)
    }
    
    /**
     重置分发处理规则
     */
    private func resetMTRule() ->Void{
        MTEngine.default.discardRule(self.dispatchHandleRule!)
        self.dispatchHandleRule = self.mt_limitSelector(#selector(dispatchFailRequestHandler_ModeRepeat_WithModel(model:)), oncePerDuration:self.repeatTimeInterval, using: self.repeatHandleMode)
        MTEngine.default.apply(self.dispatchHandleRule!)
    }
    
    
    /**
     在此方法中替换失败请求的成功回调 (替换缓存中匹配该路径的全部失败请求)
     @param successClosure 用于替换的成功回调
     @param requestPath 被替换的失败请求路径
     */
    public func replaceFailRequestClosure(
        successClosure:@escaping TXResponseClosure,
        requestPath:String)
        -> Void
    {
        for (_,obj) in (TXFRCDManager.sharedManager().failRequestCache.cache.enumerated().reversed()) {
            guard obj is TXFailRequestModel else{
                return
            }
            if (obj as! TXFailRequestModel).path == requestPath {
                (obj as! TXFailRequestModel).successClosure = successClosure
            }
        }
    }
    
    /**
     在此方法中传入处理失败的网络请求
     @param model 失败请求模型
     @param error 失败信息
     */
    public func sendFailRequestWithModel(
        model:TXFailRequestModel,
        errorInfo:Any)
        -> Void
    {
        print("请求失败 进入失败分发中心")
        model.errorInfo = errorInfo;
        self.failRequestCache.mutableArrayValue(forKey: "cache").add(model)
    }
    
    /**
     快捷方法：分发失败请求，再请求一次(请求缓存中匹配该路径的全部失败请求)
     @param path 失败的网络请求路径
     */
    public func dispatchFailRequestOnceAgainWithRequestPath(
        path:String)
        -> Void
    {
        for (_,obj) in (TXFRCDManager.sharedManager().failRequestCache.cache.enumerated().reversed()) {
            guard obj is TXFailRequestModel else{
                return
            }
            if (obj as! TXFailRequestModel).path == path {
                self.dispatchFailRequestOnceAgainWithFailModel(model: obj as! TXFailRequestModel)
            }
        }
    }
    
    /**
     快捷方法：分发失败请求，反复请求直到成功(请求缓存中匹配该路径的全部失败请求)
     @param path 失败的网络请求路径
     */
    public func dispatchFailRequestRepeatWithRequestPath(
        path:String)
        -> Void
    {
        for (_,obj) in (TXFRCDManager.sharedManager().failRequestCache.cache.enumerated().reversed()) {
            guard obj is TXFailRequestModel else{
                return
            }
            if (obj as! TXFailRequestModel).path == path {
                self.dispatchFailRequestRepeatWithFailModel(model: obj as! TXFailRequestModel)
            }
        }
    }
    
    /**
     快捷方法：分发失败请求，再请求一次
     @param model 失败的网络请求模型
     */
    public func dispatchFailRequestOnceAgainWithFailModel(
        model:TXFailRequestModel)
        -> Void
    {
        model.HandlePolicy = .TXFailRequestHandlePolicyTryAgainOnce
        self.dispatchFailRequestHandlerWithModel(model: model)
    }
    
    /**
     快捷方法：分发失败请求，反复请求直到成功
     @param model 失败的网络请求模型
     */
    public func dispatchFailRequestRepeatWithFailModel(
        model:TXFailRequestModel)
        -> Void
    {
        model.HandlePolicy = .TXFailRequestHandlePolicyRepeat
        self.dispatchFailRequestHandlerWithModel(model: model)
    }
    
    /**
     主方法：执行失败请求
     @param model 失败请求模型
     */
    public func dispatchFailRequestHandlerWithModel(
        model:TXFailRequestModel)
        -> Void
    {
        if [TXFailRequestHandlePolicy.TXFailRequestHandlePolicyDefault,TXFailRequestHandlePolicy.TXFailRequestHandlePolicyIgnore,TXFailRequestHandlePolicy.TXFailRequestHandlePolicyDisable].contains(model.HandlePolicy){
            return
        }else{
            //修改状态为处理中
            model.failRequestStatus = .TXFailRequestModelStatusProcessing
            //执行请求
            TXNetworkManager.shareManager().networkRequest(path: model.path!, params: model.params, requestType: model.requestType!, successClosure:{ (data, error) in
                    model.failRequestStatus = .TXFailRequestModelStatusDone
                    model.successClosure!(data,error)
            }, failureClosure: { (data, error, fRModel) in
                if model.HandlePolicy == .TXFailRequestHandlePolicyTryAgainOnce{
                    //单次模式失败，则标记状态为再次失败，结束任务
                    model.failRequestStatus = .TXFailRequestModelStatusFailedAgain;
                }else{
                    //若为repeat模式失败，则进入循环请求继续执行
                    self.dispatchFailRequestHandler_ModeRepeat_WithModel(model: model)
                }
            }, autoSaveFailRequest: false)
        }
    }
    
    /**
     清空全部失败请求缓存
     */
    public func cleanFRCDCache()
        -> Void
    {
        //简单清除数据
        self.failRequestCache.cache.removeAll()
    }
    
    /**
     重写属性观察方法，回收缓存空间
     */
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        //清除已经完成或设置为忽略的失败任务
        for (index, object) in self.failRequestCache.cache.enumerated().reversed() {
            if (object as! TXFailRequestModel).failRequestStatus == .TXFailRequestModelStatusDone || (object as! TXFailRequestModel).failRequestStatus == .TXFailRequestModelStatusIgnored{
                self.failRequestCache.cache.remove(at: index)
            }
        }
        //超出缓存上限，清理掉没有被处理的任务
        if (self.failRequestCache.cache.count > TXNetworkTaskCache.TXNetWorkCacheMaxCapacity) {
            //1、超出上限优先清理没有设置如何处理的失败任务以及再次尝试仍然失败的任务
            for (index, object) in self.failRequestCache.cache.enumerated().reversed() {
                if (object as! TXFailRequestModel).failRequestStatus == .TXFailRequestModelStatusPaused || (object as! TXFailRequestModel).failRequestStatus == .TXFailRequestModelStatusFailedAgain{
                    self.failRequestCache.cache.remove(at: index)
                }
            }
            //2、若缓存仍然超出上限 则清除可能正在反复执行的失败任务
            if (self.failRequestCache.cache.count > TXNetworkTaskCache.TXNetWorkCacheMaxCapacity) {
                for (index, object) in self.failRequestCache.cache.enumerated().reversed() {
                    if (object as! TXFailRequestModel).failRequestStatus == .TXFailRequestModelStatusProcessing || (object as! TXFailRequestModel).HandlePolicy == .TXFailRequestHandlePolicyRepeat{
                        self.failRequestCache.cache.remove(at: index)
                    }
                }
            }
            //3、若清理异常则直接清空缓存
            if (self.failRequestCache.cache.count > TXNetworkTaskCache.TXNetWorkCacheMaxCapacity) {
                self.cleanFRCDCache()
            }
        }
    }
    
    /**
     分发失败请求
     */
    @objc private func dispatchFailRequestHandler_ModeRepeat_WithModel(
        model:TXFailRequestModel)
        -> Void
    {
        //修改状态为处理中
        model.failRequestStatus = .TXFailRequestModelStatusProcessing;
        //执行请求
        TXNetworkManager.shareManager().networkRequest(path: model.path!, params: model.params, requestType: model.requestType!, successClosure:{ (data, error) in
            //成功则结束循环
            model.failRequestStatus = .TXFailRequestModelStatusDone
            model.successClosure!(data,error)
        }, failureClosure: { (data, error, fRModel) in
            //失败则继续请求
            self.dispatchFailRequestHandler_ModeRepeat_WithModel(model: model)
        }, autoSaveFailRequest: false)
    }
    
    
    
}
